Skip to content

Feat: Add tls_bridge.upstream_insecure to skip origin cert verification#677

Open
aslom wants to merge 1 commit into
rossoctl:mainfrom
aslom:upstream_insecure
Open

Feat: Add tls_bridge.upstream_insecure to skip origin cert verification#677
aslom wants to merge 1 commit into
rossoctl:mainfrom
aslom:upstream_insecure

Conversation

@aslom

@aslom aslom commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds an opt-in tls_bridge.upstream_insecure flag. When the TLS bridge
re-originates a decrypted request to the real origin, upstream_insecure: true
sets InsecureSkipVerify on the re-origination client so it does not verify
the origin's certificate. Default is unchanged (verify against system roots +
upstream_ca_bundle).

  • NewUpstreamClient(extraRootsPEM, insecure) — new insecure parameter.
  • TLSBridgeConfig.UpstreamInsecure (yaml: upstream_insecure) — plumbs it;
    authbridge-proxy logs a warning when enabled.
  • Test covers insecure=true accepting a self-signed origin.

Why this is needed (the rossocortex / rossoctlx use case)

rossocortex
is a local budget/credential-injection proxy that sits in front of an
LLM endpoint, and rossoctlx
is its CLI. rossocortex embeds AuthBridge (proxy-sidecar mode) as its
outbound TLS bridge: agent traffic is forwarded through AuthBridge so its
plugins (litellm-budget-track, inference-parser, placeholder-resolve)
can see and act on the request, and AuthBridge's tls_bridge terminates the
outbound TLS to do it.

The real deployments this targets point at an internal LiteLLM endpoint whose
certificate chain is signed by a private/enterprise CA
(e.g.
ete-litellm.ai-models.vpc-int.res.ibm.com). When AuthBridge's TLS bridge
re-originates to that endpoint, NewUpstreamClient verifies the origin against
system roots (+ any upstream_ca_bundle). The private CA is not in the system
trust store, so verification fails with:

[SSL: CERTIFICATE_VERIFY_FAILED] self-signed certificate in certificate chain

Today that failure forces the bridge into passthrough for the host — the
request tunnels un-inspected, so AuthBridge's budget/parser plugins never see
it. In other words, without a way to trust (or skip verifying) the private
upstream, AuthBridge cannot own the connection to an internal LiteLLM, which
defeats the reason rossocortex embeds it.

upstream_insecure gives operators of such internal endpoints a documented
escape hatch: AuthBridge can complete re-origination to the self-signed upstream
and keep the request on the inspected path. rossoctlx exposes this end-to-end so
users never edit AuthBridge YAML by hand:

  • ROSSOCORTEX_UPSTREAM_INSECURE=1 is the single user-facing switch.
  • rossoctlx forwards it into the rossocortex container on start.
  • rossocortex renders tls_bridge.upstream_insecure: true into the per-agent
    AuthBridge config it generates.

This mirrors the pattern operators already expect from curl -k,
GIT_SSL_NO_VERIFY, PGSSLMODE=require, etc. — a deliberate, logged,
opt-in relaxation for private infrastructure, off by default.

Why not just use upstream_ca_bundle?

upstream_ca_bundle is the preferred, secure option when the private CA is
available
as a PEM file — and the flag docs/commit say so explicitly. It is
not always practical in the rossocortex context:

  • The CA may not be distributable to every laptop/sandbox running rossocortex.
  • The endpoint's chain may rotate or be operator-managed out of band.
  • For a quick local dev/test loop against an internal gateway, mounting a CA is
    friction users skip — and then they silently fall back to passthrough.

So upstream_insecure is the low-friction complement, not a replacement.

What changed

File Change
authlib/tlsbridge/upstream.go NewUpstreamClient(extraRootsPEM, insecure) sets InsecureSkipVerify: insecure
authlib/config/config.go TLSBridgeConfig.UpstreamInsecure (yaml: upstream_insecure)
cmd/authbridge-proxy/main.go passes cfg.TLSBridge.UpstreamInsecure; warns when enabled
authlib/tlsbridge/upstream_test.go asserts insecure=true accepts a self-signed origin; false still rejects

Config example:

tls_bridge:
  mode: enabled
  ca_dir: /etc/rossocortex/ca
  ports: [443]
  upstream_insecure: true   # internal/self-signed LiteLLM; prefer upstream_ca_bundle when you have the CA

Test plan

  • go test ./authlib/tlsbridge/ -run TestUpstreamClient (new insecure case passes; false still rejects self-signed).
  • go build ./authlib/... && CGO_ENABLED=0 GOOS=linux go build ./cmd/authbridge-proxy/.
  • End-to-end via rossocortex: ROSSOCORTEX_UPSTREAM_INSECURE=1 rossoctlx cortex start --upstream https://<internal-litellm>; an agent LLM call returns 200 instead of a 502 self-signed error.
  • Default (flag unset) is unchanged — self-signed upstream still fails closed.

Suggested improvements / follow-ups

  1. Scope insecure per host, not globally. Today it's a single bool for the
    whole bridge. A upstream_insecure_hosts: [glob, …] (mirroring
    passthrough_hosts) would let the internal LiteLLM be trusted-insecure while
    every other origin still verifies — much smaller blast radius.

  2. Prefer upstream_ca_bundle auto-discovery. rossocortex actually ships a
    288 KB combined-ca.pem that does verify the internal endpoint on a direct
    socket. A cleaner long-term fix is to feed that bundle as upstream_ca_bundle
    so upstream_insecure isn't needed at all. Worth documenting the decision
    tree: CA bundle > per-host insecure > global insecure.

  3. Investigate the bad record MAC MITM handshake. In the rossocortex
    integration, AuthBridge's bridge handshake with the Python httpx client
    intermittently fails (tls: bad record MAC) and falls back to passthrough —
    so even with upstream_insecure, AuthBridge doesn't reliably keep the
    request on the inspected path. Likely an ALPN/h2 interaction in the minted
    leaf or terminator. Fixing this is what makes upstream_insecure actually
    deliver inspected traffic rather than just unblocking passthrough.

  4. Surface it in observability. Emit a session/stat event (or a one-time
    startup metric) when re-origination runs insecure, so an operator auditing a
    deployment can see that verification is disabled without grepping logs.

  5. Validation guardrail. Consider making upstream_insecure: true +
    upstream_ca_bundle set at the same time a validation warning (CA bundle
    wins / insecure is redundant), and refuse upstream_insecure unless
    tls_bridge.mode: enabled.

  6. Naming parity. If the envoy-sidecar path grows an equivalent, keep the
    field name identical so the two deployment shapes share one vocabulary.

Assisted-By: Claude (Anthropic AI) noreply@anthropic.com

Summary by CodeRabbit

  • New Features

    • Added an option to disable upstream TLS certificate verification for internal or self-signed origins.
    • Added configuration support for enabling this behavior and a log message when it is active.
  • Bug Fixes

    • Improved connectivity to upstream services when trusted certificate authorities are unavailable.

The TLS bridge re-originates to the real origin via NewUpstreamClient, which
verified against system roots + upstream_ca_bundle and never skipped
verification. For internal/self-signed upstreams (e.g. a private LiteLLM
endpoint) where the origin CA is unavailable, add an opt-in escape hatch:

- NewUpstreamClient(extraRootsPEM, insecure): sets InsecureSkipVerify when
  insecure is true.
- TLSBridgeConfig.UpstreamInsecure (yaml: upstream_insecure): plumbs the flag
  from config; authbridge-proxy logs a warning when enabled.
- upstream_test.go: cover insecure=true accepting a self-signed origin.

Prefer upstream_ca_bundle when the origin CA is available.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Aleksander Slominski <aslom@us.ibm.com>
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The TLS bridge adds UpstreamInsecure configuration, passes it to NewUpstreamClient, conditionally disables upstream certificate verification, logs the setting, and tests both verification modes.

Upstream TLS verification

Layer / File(s) Summary
Upstream client TLS behavior
authbridge/authlib/config/config.go, authbridge/authlib/tlsbridge/upstream.go, authbridge/authlib/tlsbridge/upstream_test.go
TLSBridgeConfig exposes UpstreamInsecure; NewUpstreamClient applies it to InsecureSkipVerify; tests cover injected roots, verification failure, and insecure success.
Proxy configuration wiring
authbridge/cmd/authbridge-proxy/main.go
The proxy passes UpstreamInsecure to the upstream client and logs when verification is disabled.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant authbridge-proxy
  participant TLSBridgeConfig
  participant NewUpstreamClient
  participant UpstreamOrigin
  authbridge-proxy->>TLSBridgeConfig: read UpstreamInsecure
  authbridge-proxy->>NewUpstreamClient: pass CA bundle and insecure flag
  NewUpstreamClient->>UpstreamOrigin: initiate TLS connection
  UpstreamOrigin-->>NewUpstreamClient: present origin certificate
  NewUpstreamClient-->>authbridge-proxy: return configured HTTP client
Loading

Suggested reviewers: huang195

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding an opt-in upstream insecure flag to skip origin certificate verification.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@aslom

aslom commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

@huang195 I am not sure if it is the right solution - I tried to describe the problem there may be better way to do it - option to (pre)load self-signed cert for LiteLLM? Have them inluded in rossocortex ?

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@authbridge/cmd/authbridge-proxy/main.go`:
- Around line 332-338: Replace the informational log.Printf call in the
cfg.TLSBridge.UpstreamInsecure branch with slog.Warn, preserving the existing
warning message and condition. Keep the adjacent log.Fatalf error handling
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a7c6e8d5-18fc-4808-92f4-9e3d87e90d1e

📥 Commits

Reviewing files that changed from the base of the PR and between df01b1b and f4083f8.

📒 Files selected for processing (4)
  • authbridge/authlib/config/config.go
  • authbridge/authlib/tlsbridge/upstream.go
  • authbridge/authlib/tlsbridge/upstream_test.go
  • authbridge/cmd/authbridge-proxy/main.go

Comment on lines +332 to +338
up, uerr := tlsbridge.NewUpstreamClient(extra, cfg.TLSBridge.UpstreamInsecure)
if uerr != nil {
log.Fatalf("tls-bridge upstream client failed: %v", uerr)
}
if cfg.TLSBridge.UpstreamInsecure {
log.Printf("tls-bridge: upstream_insecure=true — re-origination does NOT verify the upstream TLS cert")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Use log/slog for the insecure warning.

The new log statement uses log.Printf, but per the coding guidelines, log/slog should be used for logging. Since this is an informational warning about reduced security, slog.Warn is the appropriate choice and matches the pattern used elsewhere in this file. Note that while boot-path log.Fatalf is preserved by design based on learnings, standard informational logging should still use slog.

♻️ Proposed fix
 		up, uerr := tlsbridge.NewUpstreamClient(extra, cfg.TLSBridge.UpstreamInsecure)
 		if uerr != nil {
 			log.Fatalf("tls-bridge upstream client failed: %v", uerr)
 		}
 		if cfg.TLSBridge.UpstreamInsecure {
-			log.Printf("tls-bridge: upstream_insecure=true — re-origination does NOT verify the upstream TLS cert")
+			slog.Warn("tls-bridge: upstream_insecure=true — re-origination does NOT verify the upstream TLS cert")
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
up, uerr := tlsbridge.NewUpstreamClient(extra, cfg.TLSBridge.UpstreamInsecure)
if uerr != nil {
log.Fatalf("tls-bridge upstream client failed: %v", uerr)
}
if cfg.TLSBridge.UpstreamInsecure {
log.Printf("tls-bridge: upstream_insecure=true — re-origination does NOT verify the upstream TLS cert")
}
up, uerr := tlsbridge.NewUpstreamClient(extra, cfg.TLSBridge.UpstreamInsecure)
if uerr != nil {
log.Fatalf("tls-bridge upstream client failed: %v", uerr)
}
if cfg.TLSBridge.UpstreamInsecure {
slog.Warn("tls-bridge: upstream_insecure=true — re-origination does NOT verify the upstream TLS cert")
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@authbridge/cmd/authbridge-proxy/main.go` around lines 332 - 338, Replace the
informational log.Printf call in the cfg.TLSBridge.UpstreamInsecure branch with
slog.Warn, preserving the existing warning message and condition. Keep the
adjacent log.Fatalf error handling unchanged.

Sources: Coding guidelines, Learnings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: New/ToDo

Development

Successfully merging this pull request may close these issues.

2 participants